const robot = require('robotjs');
const fs = require('fs');
const { PNG } = require('pngjs');

const Tesseract = require('tesseract.js');
const dayjs=require('dayjs');
function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
// 判断像素是否为黄色，可根据实际情况调整阈值
function isYellow(r, g, b) {
    // 简单的黄色范围判断，可按需调整
    return r === 255 && g ===255 && b ===0;
}
function isBlue(r, g, b) {
    // 简单的黄色范围判断，可按需调整
    return r === 0 && g ===0 && b ===255;
}
const { execSync } = require('child_process');

const path = require("path");

//粘贴
function pasteFromClipboard(text) {
    try {
        // 对换行符和单引号进行转义处理
        const escapedText = text.replace(/\n/g, "\t").replace(/'/g, "''");
        // 使用 Out-String 确保换行符被正确处理
        execSync(`powershell -command "Write-Output '${escapedText}' | Out-String -Stream | Set-Clipboard"`);
        // Windows 系统
        robot.keyTap('v','control')
    } catch (error) {
        console.error('粘贴失败:', error);
    }
}
const rectView={
    getValueByPosArr(posArr,rect){
        return rect.data[posArr[0]+posArr[1]*rect.width]
    },
    //通过花费得到的收益
    initItem(item,all){
        const rect1=this.rect1
        const rect2=this.rect2
        const posArr1=this.posArr1
        const posArr2=this.posArr2

        while(item.price>0){
            const pos1=[posArr1[item.id][0]+posArr2[item.curFee][0],posArr1[item.id][1]+posArr2[item.curFee][1]]
            const pos2=posArr2[item.curFee]
            item.curFee++
            item.price--
            if(this.getValueByPosArr(pos1,rect1)===this.getValueByPosArr(pos2,rect2)){
                item.val++
            }else if(!all){
                break
            }else if(all!==true){
                all--
            }
        }
    },
    //大图中查找小图,获取最大的相似区域
    getMaxList(rect1,rect2,pipei){
        this.rect1=rect1
        this.rect2=rect2
        this.posArr1=[]
        this.posArr2=[]
        this.taskList=[]
        const posArr1=this.posArr1
        const posArr2=this.posArr2


// 初始化任务列表
        let taskList=this.taskList
        let id = 0;

        const len2=rect2.width*rect2.height
// 遍历 bigRect 的每个像素点，生成任务
        const h1=rect1.height-rect2.height+1
        const w1=rect1.width-rect2.width+1
        for (let y = 0; y < h1; y++) {
            for (let x = 0; x < w1; x++) {
                posArr1.push([x,y])
                taskList.push({
                    id: id,          // 唯一任务 ID
                    price: len2,     // 价格
                    curFee:0,   //花费
                    val:0,    //价值
                });
                id++
            }
        }
        for (let y = 0; y < rect2.height; y++) {
            for (let x = 0; x < rect2.width; x++) {
                posArr2.push([x,y])
            }
        }

        //一直找到val最大的，
        let maxVal=0

        let isRunning=true

        while (isRunning){
            let maxList=[]
            taskList.forEach( (item)=>{
                this.initItem(item)
                if (item.val > maxVal) {
                    maxVal = item.val
                    maxList=[item]
                }else if (item.val === maxVal) {
                    maxList.push(item)
                }
            })
            if(taskList.length===maxList.length){
                maxList=[]
                taskList.forEach((item)=>{
                    this.initItem(item,10)
                    if (item.val > maxVal) {
                        maxVal = item.val
                        maxList=[item]
                    }else if (item.val === maxVal) {
                        maxList.push(item)
                    }
                })
            }
            if(taskList.length===maxList.length||maxList.length==0){
                isRunning=false
            }else{
                taskList=maxList
            }

        }

        if(taskList.length){
            taskList.forEach((item)=>{
                item.x=posArr1[item.id][0]
                item.y=posArr1[item.id][1]
                item.width=rect2.width
                item.height=rect2.height
                item.pipei=parseInt((item.val*100/item.curFee))
            })
        }
        return taskList


    },

}
const baseView={
    async hideAllWindows(){
        // 获取屏幕尺寸
        const screenSize = robot.getScreenSize();
        const width = screenSize.width;
        const height = screenSize.height;
        // console.log('屏幕宽度:', width, '屏幕高度:', height);
        robot.moveMouse(width,height)
        robot.mouseClick()
    },
    getRectInScreen(imgInfo){
        const width = imgInfo.width;
        const height = imgInfo.height;
        const screenshot = robot.screen.capture(imgInfo.x, imgInfo.y, width, height);
        const rect={
            width: width,
            height: height,
            data:[]
        }
        // 将截图数据复制到 PNG 对象
        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                const pos = y * width + x;
                const imgPos = pos * 4;
                const r=screenshot.image.readUInt8(imgPos + 2)
                const g=screenshot.image.readUInt8(imgPos + 1)
                const b=screenshot.image.readUInt8(imgPos)
                rect.data[pos]=parseInt((r+b+g)/3)
            }
        }
        return rect
    },
    //获取屏幕截图
    getCroppedPngInScreen(imgInfo){
        const screenshot = robot.screen.capture(imgInfo.x, imgInfo.y, imgInfo.width, imgInfo.height);
        // 根据 imgInfo 裁剪截图
        const croppedPng = new PNG({
            width: imgInfo.width,
            height: imgInfo.height
        });
        for (let y = 0; y < croppedPng.height; y++) {
            for (let x = 0; x < croppedPng.width; x++) {
                const pos = y * croppedPng.width + x;
                const imgPos = pos * 4;
                const r=screenshot.image.readUInt8(imgPos + 2)
                const g=screenshot.image.readUInt8(imgPos + 1)
                const b=screenshot.image.readUInt8(imgPos)
                const a=screenshot.image.readUInt8(imgPos+3)
                croppedPng.data[imgPos] = r; // Red
                croppedPng.data[imgPos + 1] = g; // Green
                croppedPng.data[imgPos + 2] = b; // Blue
                croppedPng.data[imgPos + 3] = a; // Alpha
            }
        }

        return croppedPng
    },
    getLocalRect(f1){
        const t1Buffer = fs.readFileSync(f1);
        const t1Png = PNG.sync.read(t1Buffer);
        const height=t1Png.height
        const width=t1Png.width
        const rect={
            width: width,
            height: height,
            data:[]
        }
        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                const pos = y * width + x;
                const imgPos = pos * 4;
                const r=t1Png.data[imgPos]
                const g=t1Png.data[imgPos + 1]
                const b=t1Png.data[imgPos + 2]
                rect.data[pos]=parseInt((r+b+g)/3)
            }
        }
        return rect
    },
    compareRect(bigRect,smallRect){
        const bigData=bigRect.data
        const smallData=smallRect.data
        let num=0
        let len=0
        for (let y = 0; y < smallRect.height; y++) {
            for (let x = 0; x < smallRect.width; x++) {
                const pos = (y * bigRect.width + x)
                if(bigData[pos]===smallData[pos]){
                    num++
                }
                len++
            }
        }
        return (num*100/len)
    },
    //识别图片中的文字
    async getTextByPngInScreenShot(croppedPng,img){

        // 将 PNG 对象转换为 Uint8Array
        const pngBuffer = PNG.sync.write(croppedPng);

        //识别屏幕中imgInfo位置的文字
        const res=await Tesseract.recognize(
            new Uint8Array(pngBuffer),
            'eng',
        )
        return res.data.text.trim()
    },
    getRectInLocal(f1){
        const t1Buffer = fs.readFileSync(f1);
        const t1Png = PNG.sync.read(t1Buffer);
        const height=t1Png.height
        const width=t1Png.width
        const rect={
            width: width,
            height: height,
            data:[]
        }
        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                const pos = y * width + x;
                const imgPos = pos * 4;
                const r=t1Png.data[imgPos]
                const g=t1Png.data[imgPos + 1]
                const b=t1Png.data[imgPos + 2]
                rect.data[pos]=parseInt((r+b+g)/3)
            }
        }
        return rect
    },
    getRectInLocal(f1){
        const t1Buffer = fs.readFileSync(f1);
        const t1Png = PNG.sync.read(t1Buffer);
        const height=t1Png.height
        const width=t1Png.width
        const rect={
            width: width,
            height: height,
            data:[]
        }
        for (let y = 0; y < height; y++) {
            for (let x = 0; x < width; x++) {
                const pos = y * width + x;
                const imgPos = pos * 4;
                const r=t1Png.data[imgPos]
                const g=t1Png.data[imgPos + 1]
                const b=t1Png.data[imgPos + 2]
                rect.data[pos]=parseInt((r+b+g)/3)
            }
        }
        return rect
    },
}

const config={
    imgInfoMap:{},
    rectMap:{}
}
if(fs.existsSync('./config.json')){
    const cacheConfig=JSON.parse(fs.readFileSync('./config.json','utf-8'))
    Object.assign(config,cacheConfig)
}

const view={
    updateImgConfig(img){
        const screenSize=robot.getScreenSize()
        const screenRect=this.getRectInScreen({x:0,y:0,width:screenSize.width,height:screenSize.height})
        const smaRect=this.getLocalRect(img)
        const list=rectView.getMaxList(screenRect,smaRect)
        if(list.length===1&&list[0].pipei===100){
            const imgInfo=list[0]
            config.imgInfoMap[img]=imgInfo
            config.rectMap[img]=smaRect
        }
    },
    //获取图片信息在屏幕中的位置
    getImgInfoInScreenShot(f1){
        const imgInfo=config.imgInfoMap[f1]
        const smaRect=this.getRectInLocal(f1)

        const bigRect=this.getRectInScreen(imgInfo)
        const pipei =this.compareRect(bigRect,smaRect)
        console.log('是否匹配',pipei,imgInfo.x,imgInfo.y,pipei)
        if(pipei>90){
            return imgInfo
        }else{
            console.log('匹配图片失败',f1)

        }
    },
    //识别图片位置中的文字
    async getTextByImg(img){
        const imgInfo=config.imgInfoMap[img]
        const croppedPng=this.getCroppedPngInScreen(imgInfo)
        return await this.getTextByPngInScreenShot(croppedPng)
    },

    isAutoPage:false,
    async showQHPage(){
        await this.hideAllWindows()
        const imgInfo=this.clickImgInScreen('./img/qhicon.png')
        await delay(2000)
        if(imgInfo){
            this.isAutoPage=this.getImgInfoInScreenShot('./img/page-top.png')
        }
    },
    async login(task){
        const imgInfo=this.getImgInfoInScreenShot(task.img)
        if(imgInfo){
            robot.moveMouse(imgInfo.x+imgInfo.width/2,imgInfo.y+imgInfo.height-20)
            robot.mouseClick()
        }else{
            await delay(1000)
            await this.login(task)
        }
    },

    async initConfig(){

        if(fs.existsSync('./config.json')){
            const cacheConfig=JSON.parse(fs.readFileSync('./config.json','utf-8'))
            Object.assign(config,cacheConfig)
        }
        // await this.initOneImg('./img/page-hasnums.png','./img/page-screen2.png')
        // fs.writeFileSync('./config.json',JSON.stringify(config,null,2))

        if(!fs.existsSync('./config.json')){

            await this.initOneImg('./img/page-top.png','./img/page-screen.png')
            await this.initOneImg('./img/page-mid.png','./img/page-screen.png')

            await this.initOneImg('./img/page-item.png','./img/page-screen.png')
            // await this.initOneImg('./img/page-macd.png','./img/page-screen.png')
            // await this.initOneImg('./img/page-kdj.png','./img/page-screen.png')
            // await this.initOneImg('./img/page-arbr.png','./img/page-screen.png')
            await this.initOneImg('./img/page-price.png','./img/page-screen.png')

            await this.initOneImg('./img/page-buy.png','./img/page-screen.png')
            await this.initOneImg('./img/page-sell.png','./img/page-screen.png')
            await this.initOneImg('./img/page-ping.png','./img/page-screen.png')

            await this.initOneImg('./img/qqmsg.png','./img/icons-screen.png')
            await this.initOneImg('./img/qhicon.png','./img/icons-screen.png')
            await this.initOneImg('./img/qqicon.png','./img/icons-screen.png')
            fs.writeFileSync('./config.json',JSON.stringify(config,null,2))
            console.log('配置ok,生成图片信息')
        }
    },
    async initOneImg(img,screenImg){
        const smaRect=this.getRectInLocal(img)
        const screenRect=this.getRectInLocal(screenImg)
        const list=rectView.getMaxList(screenRect,smaRect)
        console.log(img,list[0].pipei,list.length)
        // const png=this.getCroppedPngInLocal(list[0],screenImg)
        // fs.writeFileSync('./img/test.png', PNG.sync.write(png));
        if(list.length===1&&list[0].pipei>98){
            const {x,y,width,height}=list[0]
            config.imgInfoMap[img]={x,y,width,height}
        }else{
            console.log(list)
            throw new Error('图片匹配失败'+img)
        }
    },
    clickImgInScreen(img){
        let imgInfo=this.getImgInfoInScreenShot(img)

        if(imgInfo){
            robot.moveMouse(imgInfo.x+imgInfo.width/2,imgInfo.y+imgInfo.height/2)
            robot.mouseClick()
            return imgInfo
        }
    },
    msgList:[],
    async qqSendMsg(text=''){

        await this.hideAllWindows()
        await delay(200)
        const has1=this.clickImgInScreen('./img/qqicon.png')
        await delay(200)

        if(has1){
            this.clickImgInScreen('./img/qqmsg.png')
            pasteFromClipboard(text)

            await delay(500)
            robot.keyTap('enter')
            await delay(500)
        }
    },
    codeList:[],
    async moveMouse(x,y){

        robot.moveMouse(x,y)
    },
    async sendMSG(){
        if (this.msgList.length) {
            const tarr = ['v1.01:'+dayjs().format('YYYY-MM-DD HH:mm:ss ')];
            this.msgList.forEach(({codeName, tip,price}) => {
                tarr.push(`\n${codeName} 价格：${price}\n${tip}`);
            });
            this.msgList = [];
            await this.qqSendMsg(tarr.join(' '));
            await this.showQHPage();

        }
    },
    async listenAllCodeInit(task){
        const codeList=this.codeList
        if(this.isAutoPage){
            console.log('进入期货界面')

            const croppedPng=this.getCroppedPngInScreen( config.imgInfoMap['./img/page-hasnums.png'])
            const text=await this.getTextByPngInScreenShot(croppedPng)
            console.log(text)

            const listLen=5
            const imgInfo0 = config.imgInfoMap['./img/page-item.png'];
            const repeatArr=[]
            for(let i=0;i<listLen;i++){
                const imgInfo = {
                    x:imgInfo0.x,
                    y:imgInfo0.y+imgInfo0.height*i,
                    width:imgInfo0.width,
                    height:imgInfo0.height,
                };
                await this.moveMouse(imgInfo.x + imgInfo.width / 2, imgInfo.y + imgInfo.height / 2);
                robot.mouseClick();
                await delay(500);

                const croppedPng=this.getCroppedPngInScreen(imgInfo)
                // const pngBuffer = PNG.sync.write(croppedPng);
                // fs.writeFileSync(`./img/pic${i}.png`,pngBuffer)
                const text=await this.getTextByPngInScreenShot(croppedPng)
                const arr=text.split(' ')
                let code=arr[0]
                if(arr[0]==='SR2509'){
                    code='SA2509'
                }
                if(arr[0]==='BE2509'){
                    code='SH2509'
                }
                if(arr[0]==='SR2601'){
                    code='SA2601'
                }
                if(arr[0]==='FRER2509'){
                    code='UR2509'
                }
                if(arr[0]==='SAR2509'){
                    code='ao2509'
                }
                console.log('识别list：',code)
                if(repeatArr.indexOf(code)>-1){
                    break
                }else{
                    repeatArr.push(code)
                }
                if(this.codeMap[code]){
                    this.codeMap[code].imgInfo=imgInfo
                    const taskItem=this.codeMap[code]
                    taskItem.code=code
                    codeList.push(taskItem)
                }

            }
        }
        // console.log(codeList)
    },
    signalList:[],

    //delayEmptyTime
    async delayEmptyTime(){
        const now = dayjs();
        const nowTime = now.valueOf();
        const day = dayjs().day();

        const nineAm = dayjs(now.format('YYYY-MM-DD 09:00:00')).valueOf();
        const tenAm = dayjs(now.format('YYYY-MM-DD 10:15:00')).valueOf();
        const ten2Am = dayjs(now.format('YYYY-MM-DD 10:30:00')).valueOf();
        const elevenThirtyAm = dayjs(now.format('YYYY-MM-DD 11:30:00')).valueOf();
        const oneThirtyPm = dayjs(now.format('YYYY-MM-DD 13:30:00')).valueOf();
        const threePm = dayjs(now.format('YYYY-MM-DD 15:00:00')).valueOf();
        const ninePm = dayjs(now.format('YYYY-MM-DD 21:00:00')).valueOf();
        const oneAm = dayjs(now.format('YYYY-MM-DD 01:00:00')).valueOf();
        const nextDayNineAm = dayjs(now.add(1, 'day').format('YYYY-MM-DD 09:00:00')).valueOf();
        let durTime=0
        if(day === 6 || day === 0){
            durTime = nextDayNineAm - nowTime;
            console.log('等待第二天09:00', durTime);
        }else if (nowTime > oneAm&&nowTime < nineAm) {
            durTime = nineAm - nowTime;
            console.log('等待9:00', durTime);
        } else if (nowTime > tenAm && nowTime < ten2Am) {
            durTime = ten2Am - nowTime;
            console.log('等待10:30', durTime);
        } else if (nowTime > elevenThirtyAm && nowTime < oneThirtyPm) {
            durTime = oneThirtyPm - nowTime;
            console.log('等待13:30', durTime);
        } else if (nowTime > threePm && nowTime < ninePm) {
            durTime = ninePm - nowTime;
            console.log('等待21:00', durTime);
        }
        if(durTime>0){
            await delay(durTime);
            console.log('等待后，程序启动')
            await this.showQHPage()
            await this.qqSendMsg('等待后，程序启动');
            await this.showQHPage();
        }
    },
    async _getColorSignal(){
        const imgInfo=config.imgInfoMap['./img/page-mid.png']
        const t1Png = this.getCroppedPngInScreen(imgInfo)

        const height=t1Png.height
        const width=t1Png.width
        const colorArr=['255,0,0','255,0,1','255,0,2','0,128,0','0,128,1','0,128,2']
        const tipArr=['抄底,多','急涨,多','冲底,多','空顶,空','急跌,空','冲顶,空']
        const typeArr=['buy','buy','buy','sell','sell','sell']
        const signal={
            index:-1,
            color:'',
            tip:'',
            type:'',
            time:dayjs().valueOf()
        }
        if(this.isDev){
            this.isDev=false
            signal.index=1
            signal.color=colorArr[signal.index]
            signal.tip=tipArr[signal.index]
            signal.type=typeArr[signal.index]
            return signal
        }
        for (let x = width-1; x >=0&&signal.index===-1; x--) {
            for (let y = 0; y < height; y++) {
                const pos = y * width + x;
                const imgPos = pos * 4;
                const r=t1Png.data[imgPos]
                const g=t1Png.data[imgPos + 1]
                const b=t1Png.data[imgPos + 2]
                const key=[r,g,b].join(",")
                const index=colorArr.indexOf(key)
                if(index>-1){
                    signal.index=index
                    signal.color=key
                    signal.tip=tipArr[index]
                    signal.type=typeArr[index]
                    break
                }
            }
        }
        if(signal.index>-1){
            return signal
        }

    },
    async getColorSignal(taskItem){
        let signal=await this._getColorSignal()
        const preSignal=taskItem.signal
        //2分钟内相同的信号
        if(preSignal&&signal&&signal.index===preSignal.index&&signal.time<preSignal.time+1000*60*2){
            signal=null
        }
        if(signal&&signal.type==='buy'&&taskItem.hasNum>=3){
            signal=null
        }
        if(signal&&signal.type==='sell'&&taskItem.hasNum<=-3){
            signal=null
        }
        if(signal){
            const price=await this.getTextByImg('./img/page-price.png')
            signal.code=taskItem.code
            signal.codeName=taskItem.codeName
            signal.price=price
            if(signal.type==='buy'){
                if(taskItem.hasNum<0){
                    signal.type='ping'
                }
                taskItem.hasNum++

            }else if(signal.type==='sell'){
                if (taskItem.hasNum > 0) {
                    signal.type = 'ping'
                }
                taskItem.hasNum--
            }
            taskItem.signal=signal
            this.saveCodeMap()
            return signal
        }
    },
    async listenAllCodeList(task){
        while (this.isAutoPage) {
            const codeList = this.codeList;
            const curTime = dayjs().format('HH:mm:ss');
            for (let i = 0; i < codeList.length; i++) {
                const taskItem = codeList[i];
                if(taskItem.timeType===1&&!(curTime>'09:00:00'&&curTime<'15:00:00')){
                    continue
                }
                if(taskItem.timeType===2&&!(curTime>'09:00:00'&&curTime<'23:00:00')){
                    continue
                }
                if(taskItem.timeType===3&&curTime<'09:00:00'&&curTime>'01:00:00'){
                    continue
                }
                const imgInfo = taskItem.imgInfo;
                robot.moveMouse(imgInfo.x + imgInfo.width / 2, imgInfo.y + imgInfo.height / 2);
                robot.mouseClick();
                await delay(1000);
                console.log('监听：', taskItem.code);
                const signal = await this.getColorSignal(taskItem);
                if (signal) {
                    await this.runActionSignal(signal)

                }
            }

            this.isAutoPage = this.getImgInfoInScreenShot('./img/page-top.png');

            await this.delayEmptyTime();
        }
    },
    async runActionSignal(signal){
        console.log('存在信号', signal);

        //执行买入或者卖出
        if(signal.type==='buy'){
            const imgInfo = config.imgInfoMap['./img/page-buy.png'];
            await this.moveMouse(imgInfo.x + imgInfo.width / 2, imgInfo.y + imgInfo.height / 2)
            robot.mouseClick();
        }else if(signal.type==='sell'){
            const imgInfo = config.imgInfoMap['./img/page-sell.png'];
            await this.moveMouse(imgInfo.x + imgInfo.width / 2, imgInfo.y + imgInfo.height / 2)
            robot.mouseClick();
        }else if(signal.type==='ping'){
            const imgInfo = config.imgInfoMap['./img/page-ping.png'];
            await this.moveMouse(imgInfo.x + imgInfo.width / 2, imgInfo.y + imgInfo.height / 2)
            robot.mouseClick();
        }
        //发送qq消息
        this.msgList.push(signal)
        await this.sendMSG()
    },
    isDev:false,
    isLog:true,
    //列表可用的
    codeMap:{
        'SH2509':{
            codeName:'烧碱2509',
            timeType:2,
            hasNum:2,//持仓情况
        },
        'SA2509':{
            codeName:'纯碱2509',
            timeType:2,
            hasNum:3,//持仓情况
        },
        'SA2601':{
            codeName:'纯碱2601',
            timeType:2,
            hasNum:0,//持仓情况
        },
        'UR2509':{
            codeName:'尿素2509',
            timeType:1,//只有白天有
            hasNum:1,//持仓情况
        },
        'ao2509':{
            codeName:'氧化铝2509',
            timeType:3,
            hasNum:-3,//持仓情况
        },
    },
    saveCodeMap(){
        const cache={}
        for(let code in this.codeMap){
            cache[code]={
                code,
                codeName:this.codeMap[code].codeName,
                hasNum:this.codeMap[code].hasNum,
                signal:this.codeMap[code].signal,
            }
        }
        fs.writeFileSync('./codeMap.json',JSON.stringify(cache,null,2))
    },
    initCodeMap(){
        if(fs.existsSync('./codeMap.json')){
            const cache=JSON.parse(fs.readFileSync('./codeMap.json','utf-8'))
            for(let code in cache){
                Object.assign(this.codeMap[code],cache[code])
            }

        }
    },
    async init(){

        await this.initConfig()
        await this.initCodeMap()
        // await this.delayEmptyTime()

        await this.showQHPage()
        await delay(1000)

        await this.listenAllCodeInit()
        await this.listenAllCodeList()
        // await this.qqSendMsg('测试信息\n21\n2')
        await this.hideAllWindows()
        console.log('程序退出结束')
    },
}
Object.assign(view,baseView)
view.init()

